#include "BondDealTermRange.h"

#include <core/QbLogger.h>
#include <core/Utility.h>

#include <fstream>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#define new DEBUG_NEW
#endif

CBondDealTermRange& CBondDealTermRange::instance() {
  static CBondDealTermRange s_range;
  return s_range;
}

CBondDealTermRange::CBondDealTermRange() {
  m_diffInterest = diffType_CDC;
  m_diffCredit = diffType_CDC;
  m_diffNCD = diffType_CDC;
  m_diffNCDPrimary = diffType_CDC;
}

CBondDealTermRange::~CBondDealTermRange() {}

void CBondDealTermRange::InitDefaultRange(
    sBondDealTermRgUnit& unit, CBondDealTermRange::emBondType range) {
  switch (range) {
    case CBondDealTermRange::bondType_Interest: {
      if (strcmp(unit.m_term, "1Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "0M");
        FIELDCOPY(unit.m_rangeRight, "1Y");
      } else if (strcmp(unit.m_term, "2Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "1Y");
        FIELDCOPY(unit.m_rangeRight, "2Y");
      } else if (strcmp(unit.m_term, "3Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "2Y");
        FIELDCOPY(unit.m_rangeRight, "3Y");
      } else if (strcmp(unit.m_term, "5Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "3Y");
        FIELDCOPY(unit.m_rangeRight, "5Y");
      } else if (strcmp(unit.m_term, "7Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "5Y");
        FIELDCOPY(unit.m_rangeRight, "7Y");
      } else if (strcmp(unit.m_term, "10Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "7Y");
        FIELDCOPY(unit.m_rangeRight, "10Y");
      } else if (strcmp(unit.m_term, "15Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "10Y");
        FIELDCOPY(unit.m_rangeRight, "15Y");
      } else if (strcmp(unit.m_term, "20Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "15Y");
        FIELDCOPY(unit.m_rangeRight, "20Y");
      } else if (strcmp(unit.m_term, "30Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "20Y");
        FIELDCOPY(unit.m_rangeRight, "30Y");
      } else if (strcmp(unit.m_term, "50Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "30Y");
        FIELDCOPY(unit.m_rangeRight, "50Y");
      } else if (strcmp(unit.m_term, "LangTerm") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "10Y");
        FIELDCOPY(unit.m_rangeRight, "50Y");
      }
      break;
    }
    case CBondDealTermRange::bondType_Credit: {
      if (strcmp(unit.m_term, "1M") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "0M");
        FIELDCOPY(unit.m_rangeRight, "1M");
      } else if (strcmp(unit.m_term, "3M") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "1M");
        FIELDCOPY(unit.m_rangeRight, "3M");
      } else if (strcmp(unit.m_term, "6M") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "3M");
        FIELDCOPY(unit.m_rangeRight, "6M");
      } else if (strcmp(unit.m_term, "1Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "6M");
        FIELDCOPY(unit.m_rangeRight, "1Y");
      } else if (strcmp(unit.m_term, "2Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "1Y");
        FIELDCOPY(unit.m_rangeRight, "2Y");
      } else if (strcmp(unit.m_term, "3Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "2Y");
        FIELDCOPY(unit.m_rangeRight, "3Y");
      } else if (strcmp(unit.m_term, "4Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "3Y");
        FIELDCOPY(unit.m_rangeRight, "4Y");
      } else if (strcmp(unit.m_term, "5Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "4Y");
        FIELDCOPY(unit.m_rangeRight, "5Y");
      } else if (strcmp(unit.m_term, "7Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "5Y");
        FIELDCOPY(unit.m_rangeRight, "7Y");
      } else if (strcmp(unit.m_term, "10Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "7Y");
        FIELDCOPY(unit.m_rangeRight, "10Y");
      }
      break;
    }
    case CBondDealTermRange::bondType_NCDPrimary: {
      if (strcmp(unit.m_term, "临到期") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "0M");
        FIELDCOPY(unit.m_rangeRight, "0.5M");
      } else if (strcmp(unit.m_term, "1M") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "0.5M");
        FIELDCOPY(unit.m_rangeRight, "1.5M");
      } else if (strcmp(unit.m_term, "2M") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "1.5M");
        FIELDCOPY(unit.m_rangeRight, "3M");
      } else if (strcmp(unit.m_term, "3M") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "3M");
        FIELDCOPY(unit.m_rangeRight, "6M");
      } else {
        FIELDCOPY(unit.m_rangeLeft, "6M");
        FIELDCOPY(unit.m_rangeRight, "12M");
      }
      break;
    }
    case CBondDealTermRange::bondType_NCD:  // 固收综合屏NCD二级成交
    {
      if (strcmp(unit.m_term, "15D") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "0M");
        FIELDCOPY(unit.m_rangeRight, "0.5M");
      } else if (strcmp(unit.m_term, "1M") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "0M");
        FIELDCOPY(unit.m_rangeRight, "1M");
      } else if (strcmp(unit.m_term, "2M") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "1M");
        FIELDCOPY(unit.m_rangeRight, "2M");
      } else if (strcmp(unit.m_term, "3M") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "2M");
        FIELDCOPY(unit.m_rangeRight, "3M");
      } else if (strcmp(unit.m_term, "6M") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "3M");
        FIELDCOPY(unit.m_rangeRight, "6M");
      } else if (strcmp(unit.m_term, "9M") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "6M");
        FIELDCOPY(unit.m_rangeRight, "9M");
      } else if (strcmp(unit.m_term, "1Y") == 0) {
        FIELDCOPY(unit.m_rangeLeft, "9M");
        FIELDCOPY(unit.m_rangeRight, "12M");
      }
      break;
    }
    default:
      break;
  }
}

void CBondDealTermRange::UpdateRange(xQBBondDealTermRgAck* pAck, bool bInit) {
  if (!pAck) return;
  for (auto itMatrix : pAck->m_matrixTerm) {
    map<string, sBondDealTermRgUnit>* pMap = nullptr;
    switch (itMatrix.m_nRate) {
      case CBondDealTermRange::bondType_Interest:
        pMap = &m_mapInterestRange;
        if (itMatrix.m_diffType >= 0) m_diffInterest = itMatrix.m_diffType;
        break;
      case CBondDealTermRange::bondType_Credit:
        pMap = &m_mapCreditRange;
        if (itMatrix.m_diffType >= 0) m_diffCredit = itMatrix.m_diffType;
        break;
      case CBondDealTermRange::bondType_NCDPrimary:
        pMap = &m_mapNCDPrimaryRange;
        if (itMatrix.m_diffType >= 0) m_diffNCDPrimary = itMatrix.m_diffType;
        break;
      case CBondDealTermRange::bondType_NCD:
        pMap = &m_mapNCDRange;
        if (itMatrix.m_diffType >= 0) m_diffNCD = itMatrix.m_diffType;
        break;
      default:
        break;
    }
    if (pMap == nullptr) continue;
    for (auto itList : itMatrix.m_listTerm) {
      sBondDealTermRgUnit& unit = (*pMap)[itList.m_term];
      if (bInit) {
        unit = itList;
      } else {
        int nCol = unit.m_nCol;
        unit = itList;
        unit.m_nCol = nCol;
      }

      unit.m_daysLeft = CalcDays(unit.m_rangeLeft);
      if (unit.m_daysLeft <= 0)
        unit.m_daysLeft = -1;  // 左开右闭，0D需要特殊处理
      unit.m_daysRight = CalcDays(unit.m_rangeRight);
    }
  }
}

int CBondDealTermRange::GetDiffType(CBondDealTermRange::emBondType nType) {
  int nDiff = -1;
  switch (nType) {
    case bondType_Interest:
      nDiff = m_diffInterest;
      break;
    case bondType_Credit:
      nDiff = m_diffCredit;
      break;
    case bondType_NCDPrimary:
      nDiff = m_diffNCDPrimary;
      break;
    case bondType_NCD:
      nDiff = m_diffNCD;
      break;
    default:
      break;
  }
  return nDiff;
}

bool CBondDealTermRange::GetRange(sBondDealTermRgUnit& termRg,
                                  CBondDealTermRange::emBondType nType) {
  if (termRg.m_term[0] == 0) {
    // ASSERT(0);
    log_debug("bond deal term range get range term is null !");
    return false;
  }
  map<string, sBondDealTermRgUnit>* pMap = nullptr;
  switch (nType) {
    case CBondDealTermRange::bondType_Interest:
      pMap = &m_mapInterestRange;
      break;
    case CBondDealTermRange::bondType_Credit:
      pMap = &m_mapCreditRange;
      break;
    case CBondDealTermRange::bondType_NCDPrimary:
      pMap = &m_mapNCDPrimaryRange;
      break;
    case CBondDealTermRange::bondType_NCD:
      pMap = &m_mapNCDRange;
      break;
    default:
      break;
  }
  if (pMap == nullptr) return false;
  if (pMap->find(termRg.m_term) == pMap->end()) return false;
  termRg = pMap->at(termRg.m_term);
  return true;
}

bool CBondDealTermRange::IsInited() {
  if (m_mapCreditRange.size() > 0) return true;
  if (m_mapInterestRange.size() > 0) return true;
  if (m_mapNCDRange.size() > 0) return true;
  if (m_mapNCDPrimaryRange.size() > 0) return true;
  return false;
}

bool CBondDealTermRange::GetRangeColumn(CBondDealTermRange::emBondType nType,
                                        int nDays, std::set<int>& setResult) {
  map<string, sBondDealTermRgUnit>* pMap = nullptr;
  switch (nType) {
    case CBondDealTermRange::bondType_Interest:
      pMap = &m_mapInterestRange;
      break;
    case CBondDealTermRange::bondType_Credit:
      pMap = &m_mapCreditRange;
      break;
    case CBondDealTermRange::bondType_NCDPrimary:
      pMap = &m_mapNCDPrimaryRange;
      break;
    case CBondDealTermRange::bondType_NCD:
      pMap = &m_mapNCDRange;
      break;
    default:
      break;
  }
  if (pMap == nullptr) return false;

  for (map<string, sBondDealTermRgUnit>::iterator itor = pMap->begin();
       itor != pMap->end(); ++itor) {
    sBondDealTermRgUnit& unit = itor->second;
    if (nDays > unit.m_daysLeft && nDays <= unit.m_daysRight) {
      setResult.insert(unit.m_nCol);
    }
  }
  return setResult.size() > 0;
}

int CBondDealTermRange::CalcDays(const char* pStr) {
  if (!pStr) return -1;
  int nDays = -1;
  int nStrLen = strlen(pStr);
  if (nStrLen <= 0) return nDays;

  double fRange = atof(pStr);
  char cUnit = pStr[nStrLen - 1];
  int integer = (int)fRange;
  double fracitional = fRange - integer;
  if (cUnit == 'm' || cUnit == 'M') {  // 范围为月
    nDays = integer / 12 * 365 + (integer % 12) * 30 +
            std::lround(fracitional * 30);
  } else if (cUnit == 'd' || cUnit == 'D') {
    nDays = std::lround(fRange);
  } else {  // if(cUnit == 'Y' || cUnit == 'y'){
    nDays = std::lround(fRange * 365);
  }
  return nDays;
}

map<string, sBondDealTermRgUnit>* CBondDealTermRange::GetMap(
    CBondDealTermRange::emBondType nType) {
  map<string, sBondDealTermRgUnit>* pMap = nullptr;

  switch (nType) {
    case CBondDealTermRange::bondType_Interest:
      pMap = &m_mapInterestRange;
      break;
    case CBondDealTermRange::bondType_Credit:
      pMap = &m_mapCreditRange;
      break;
    case CBondDealTermRange::bondType_NCDPrimary:
      pMap = &m_mapNCDPrimaryRange;
      break;
    case CBondDealTermRange::bondType_NCD:
      pMap = &m_mapNCDRange;
      break;
    default:
      break;
  }

  return pMap;
}
